package diskScheduling;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

/**
 * 磁盘调度
 * 58 18 160 38 55 39 90 150 184 0
 */
public class DiskScheduling {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入磁盘调度的序列，并以0结束:");
        List<Integer> list = new ArrayList<>();
        while (sc.hasNextInt()) {
            int next = sc.nextInt();
            if (next == 0) {
                break;
            } else {
                list.add(next);
            }
        }

        System.out.print("请输入从第几号扇区开始调度:");
        int begin = sc.nextInt();

        System.out.println("请选择调度方式：");
        System.out.println("1.先来先服务FCFS");
        System.out.println("2.最短寻道时间优先SSTF");
        System.out.println("3.电梯调度算法SCAN");

        while (true) {
            System.out.print("请输入调度方式对应的序号:");
            int select = sc.nextInt();
            switch (select) {
                case 1:
                    System.out.println("你选择了先来先服务算法FCFS，扫描顺序如下：");
                    fcfs(list, begin);
                    break;
                case 2:
                    System.out.println("你选择了最短寻道时间优先算法SSTF，扫描顺序如下：");
                    sstf(new ArrayList<Integer>(list), begin);
                    break;
                case 3:
                    System.out.println("你选择了电梯调度算法SCAN，请选择扇区扫描方向");
                    System.out.println("1.由内向外");
                    System.out.println("2.由外向内");
                    System.out.print("请输入扫描方向对应的序号:");
                    boolean direction = "2".equals(sc.next());
                    System.out.println("扫描顺序如下：");
                    scan(list, begin, direction);
                    break;
            }
        }
    }

    /**
     * 先来先服务算法
     *
     * @param list  调度序列
     * @param begin 起始扇区
     */
    public static void fcfs(List<Integer> list, int begin) {
        //寻道长度
        double length = 0;
        for (Integer integer : list) {
            System.out.print(integer + " ");
            length += Math.abs(begin - integer);
            begin = integer;
        }
        System.out.println("\n平均寻道长度为:" + (length / list.size()));
    }

    /**
     * 最短寻道时间优先算法
     *
     * @param list  调度序列
     * @param begin 起始扇区
     */
    public static void sstf(List<Integer> list, int begin) {
        //序列长度
        int listSize = list.size();
        double length = 0;
        //新建一个数组保存最短序列
        int[] shortestPath = new int[listSize];
        for (int i = 0; i < listSize; i++) {
            int index = 0, min = Math.abs(begin - list.get(0));
            for (int j = 1; j < listSize; j++) {
                if (Math.abs(begin - list.get(j)) < min) {
                    index = j;
                    min = Math.abs(begin - list.get(j));
                }
            }
            shortestPath[i] = list.get(index);
            length += min;
            begin = list.get(index);
            list.set(index, Integer.MAX_VALUE);
        }
        for (Integer path : shortestPath) {
            System.out.print(path + " ");
        }
        System.out.println("\n平均寻道长度:" + (length / listSize));
    }

    /**
     * 电梯调度算法
     *
     * @param list      调度序列
     * @param begin     起始扇区
     * @param direction 方向，true:由外向内,false:由内向外
     */
    public static void scan(List<Integer> list, int begin, boolean direction) {
        int listSize = list.size();
        Collections.sort(list);
        int[] path = new int[listSize];
        int num = 0;
        double length = 0;
        if (direction) {//由外向内
            for (int i = 0; i < listSize; i++) {
                if (list.get(i) >= begin) {
                    path[num++] = list.get(i);
                    length += Math.abs(list.get(i) - begin);
                    begin = list.get(i);
                }
            }
            int rest = listSize - num - 1;
            while (rest >= 0) {
                path[num++] = list.get(rest);
                length += Math.abs(list.get(rest) - begin);
                begin = list.get(rest);
                rest--;
            }
        } else {//由内向外
            for (int i = listSize - 1; i >= 0; i--) {
                if (list.get(i) <= begin) {
                    path[num++] = list.get(i);
                    length += Math.abs(list.get(i) - begin);
                    begin = list.get(i);
                }
            }
            int rest = num;
            while (rest < listSize) {
                path[num++] = list.get(rest);
                length += Math.abs(list.get(rest) - begin);
                begin = list.get(rest);
                rest++;
            }
        }
        for (Integer integer : path) {
            System.out.print(integer + " ");
        }
        System.out.println("\n平均寻道长度为:" + (length / listSize));
    }
}
